﻿using System;
using System.Data.SqlClient;
using System.Data;
using System.Collections.Generic;

namespace Sixeyed.CodeGeneration.Generation.Mapping
{
    /// <summary>
    /// Maps known SQL Server parameter types to .NET types
    /// </summary>
    public static class SqlParameterTypeMap
    {
        private static List<DbTypeMapEntry> _DbTypeList = new List<DbTypeMapEntry>();

        /// <summary>
        /// Populates the map of known SqlDbType, DbType and framework types
        /// </summary>
        static SqlParameterTypeMap()
        {
            _DbTypeList.Add(new DbTypeMapEntry(typeof(bool), DbType.Boolean, SqlDbType.Bit));
            _DbTypeList.Add(new DbTypeMapEntry(typeof(byte), DbType.Double, SqlDbType.TinyInt));
            _DbTypeList.Add(new DbTypeMapEntry(typeof(byte[]), DbType.Binary, SqlDbType.Image));
            _DbTypeList.Add(new DbTypeMapEntry(typeof(DateTime), DbType.DateTime, SqlDbType.DateTime));
            _DbTypeList.Add(new DbTypeMapEntry(typeof(Decimal), DbType.Decimal, SqlDbType.Decimal));
            _DbTypeList.Add(new DbTypeMapEntry(typeof(double), DbType.Double, SqlDbType.Float));
            _DbTypeList.Add(new DbTypeMapEntry(typeof(Guid), DbType.Guid, SqlDbType.UniqueIdentifier));
            _DbTypeList.Add(new DbTypeMapEntry(typeof(Int16), DbType.Int16, SqlDbType.SmallInt));
            _DbTypeList.Add(new DbTypeMapEntry(typeof(Int32), DbType.Int32, SqlDbType.Int));
            _DbTypeList.Add(new DbTypeMapEntry(typeof(Int64), DbType.Int64, SqlDbType.BigInt));
            _DbTypeList.Add(new DbTypeMapEntry(typeof(object), DbType.Object, SqlDbType.Variant));
            _DbTypeList.Add(new DbTypeMapEntry(typeof(string), DbType.String, SqlDbType.VarChar));
            _DbTypeList.Add(new DbTypeMapEntry(typeof(string), DbType.String, SqlDbType.NVarChar));
            _DbTypeList.Add(new DbTypeMapEntry(typeof(string), DbType.String, SqlDbType.NChar));
            _DbTypeList.Add(new DbTypeMapEntry(typeof(string), DbType.String, SqlDbType.NText));
        }

        /// <summary>
        /// Gets the .NET type from the SQL Server data type of the parameter
        /// </summary>
        /// <param name="parameter">Parameter with SQL data type</param>
        /// <returns>>.NET framework type</returns>
        public static Type GetFrameworkType(SqlParameter parameter)
        {
            Type type = null;
            foreach (DbTypeMapEntry mapEntry in _DbTypeList)
            {
                if (mapEntry.SqlDbType == parameter.SqlDbType)
                {
                    type = mapEntry.Type;
                    break;
                }
            }
            return type;
        }

        /// <summary>
        /// Gets the .NET type name from the SQL Server data type of the parameter
        /// </summary>
        /// <param name="parameter">Parameter with SQL data type</param>
        /// <returns>>.NET framework type name</returns>
        public static string GetFrameworkTypeName(SqlParameter parameter)
        {
            return GetFrameworkType(parameter).Name;
        }

        private struct DbTypeMapEntry
        {
            public Type Type;
            public DbType DbType;
            public SqlDbType SqlDbType;
            public DbTypeMapEntry(Type type, DbType dbType, SqlDbType sqlDbType)
            {
                this.Type = type;
                this.DbType = dbType;
                this.SqlDbType = sqlDbType;
            }
        }
    }
}
